package com.matt.controller.task;


import com.dotflat.util.excelUtil.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.matt.controller.api.domin.Thermometer;
import com.matt.repository.ThermometerRepository;
import com.tuo51.components.redis.RedisService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 巡检统计定时任务 xj_data
 * 
 * @author #
 * @date 2021-11-25
 */
@Component
@Configuration      //1.主要用于标记配置类，兼备Component的效果。
@EnableScheduling   // 2.开启定时任务
public class ThermometerTask
{
    @Autowired
    ThermometerRepository thermometerRepository;
    @Autowired
    private RedisService redisService;

    //删除前7天的湿度温度数据,每天23点执行
    @Scheduled(cron = "0 0 23 * * ?")
//    @Scheduled(cron = "0 0/2 * * * ?")
    private void configureTasks() {
        System.out.println("开始执行删除温度定时任务-------------------------------");
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime threeDaysAgo = now.minusDays(3);
        thermometerRepository.deleteAllByRecordIdThreeDaysAgo(threeDaysAgo);
        System.out.println("温度定时任务执行成功-------------------------------");
    }

    // 建议注入日志对象（而非System.out）
    private static final Logger log = LoggerFactory.getLogger(ThermometerTask.class); // 替换为实际类名

    @Scheduled(fixedRate = 300000)
    public void batchSaveToDb() {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            // 1. 扫描Redis中所有设备的Key（避免返回null）
            Set<String> keys = redisService.getKeys("thermometer:data:*");
            if (CollectionUtils.isEmpty(keys)) {
                log.info("Redis中无待处理的检测器数据");
                return;
            }

            // 2. 遍历每个设备的Key，批量处理
            for (String key : keys) {
                log.info("开始处理设备Key: {}", key);

                // 2.1 获取Redis列表长度（校验有效性）
                Long dataSize = redisService.getKeySize(key);
                if (dataSize == null || dataSize <= 0) {
                    log.warn("设备Key: {} 的数据长度为0，跳过处理", key);
                    continue;
                }

                // 2.2 批量读取并反序列化数据（增加异常捕获）
                List<Thermometer> thermometerList = new ArrayList<>();
                for (int i = 0; i < dataSize; i++) {
                    String jsonStr = redisService.removeFromHead(key); // 从头部弹出并删除
                    if (!StringUtils.isEmpty(jsonStr)) {
                        log.warn("设备Key: {} 的第{}条数据为空，跳过", key, i);
                        continue;
                    }

                    // 反序列化并校验
                    Thermometer thermometer = null;
                    try {
                        thermometer = objectMapper.readValue(jsonStr, Thermometer.class);
                    } catch (JsonProcessingException e) {
                        log.error("设备Key: {} 的JSON反序列化失败，JSON内容: {}", key, jsonStr, e);
                        continue; // 跳过无效数据，继续处理其他数据
                    }

                    // 校验Thermometer必填字段（根据实际数据库约束添加）
                    if (!isValidThermometer(thermometer)) {
                        log.warn("设备Key: {} 的数据不符合约束，跳过: {}", key, thermometer);
                        continue;
                    }

                    thermometerList.add(thermometer);
                }

                // 2.3 分批批量写入数据库（避免大数据量一次插入）
                if (!CollectionUtils.isEmpty(thermometerList)) {
                    // 每100条分一批（可根据数据库性能调整）
                    int batchSize = 100;
                    int total = thermometerList.size();
                    for (int i = 0; i < total; i += batchSize) {
                        int end = Math.min(i + batchSize, total);
                        List<Thermometer> batchList = thermometerList.subList(i, end);

                        try {
                            thermometerRepository.saveAll(batchList);
                            log.info("设备Key: {} 的第{}批数据（共{}条）写入数据库成功", key, i/batchSize + 1, batchList.size());
                        } catch (Exception e) {
                            log.error("设备Key: {} 的第{}批数据写入失败，数据: {}", key, i/batchSize + 1, batchList, e);
                            // 可选：将失败数据暂存到另一个Redis队列，方便后续重试
                            saveFailedDataToRedis(key, batchList, objectMapper);
                        }
                    }
                    log.info("设备Key: {} 的所有数据（共{}条）处理完成", key, total);
                }
            }
        } catch (Exception e) {
            log.error("批量写入数据库总流程失败", e); // 打印完整堆栈
        }
    }

    // 校验Thermometer对象是否符合数据库约束（根据实际字段修改）
    private boolean isValidThermometer(Thermometer thermometer) {
        if (thermometer == null) {
            return false;
        }
        // 示例：校验非空字段（根据数据库表结构补充）
        if (thermometer.getDeviceId() == null) {
            log.warn("Thermometer.deviceId 为空");
            return false;
        }
        if (thermometer.getCreateTime() == null) {
            log.warn("Thermometer.createTime 为空");
            return false;
        }
        if (StringUtils.isEmpty(thermometer.getAreaId())) {
            log.warn("Thermometer.areaId 为空");
            return false;
        }
        // 其他约束校验（如温度范围、字符串长度等）
        return true;
    }

    // 可选：将失败数据暂存到Redis，方便后续重试
    private void saveFailedDataToRedis(String originalKey, List<Thermometer> failedList, ObjectMapper objectMapper) {
        String failedKey = "thermometer:failed:" + originalKey.split(":")[2]; // 失败队列Key
        try {
            for (Thermometer t : failedList) {
                String json = objectMapper.writeValueAsString(t);
                redisService.pushFromTail(failedKey, json);
            }
            log.info("设备Key: {} 的{}条失败数据已暂存到失败队列: {}", originalKey, failedList.size(), failedKey);
        } catch (JsonProcessingException e) {
            log.error("失败数据序列化失败", e);
        }
    }
}
